using System;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Volo.Abp.DependencyInjection;
using MatrixFramework.Shared.Application.Exceptions;

namespace MatrixFramework.Shared.Application.Middleware
{
    /// <summary>
    /// 全局异常处理中间件
    /// </summary>
    public class GlobalExceptionHandlingMiddleware : ITransientDependency
    {
        private readonly RequestDelegate _next;
        private readonly ErrorHandler _errorHandler;
        private readonly ILogger<GlobalExceptionHandlingMiddleware> _logger;
        private readonly GlobalExceptionHandlingOptions _options;

        public GlobalExceptionHandlingMiddleware(
            RequestDelegate next,
            ErrorHandler errorHandler,
            ILogger<GlobalExceptionHandlingMiddleware> logger,
            IOptions<GlobalExceptionHandlingOptions> options)
        {
            _next = next;
            _errorHandler = errorHandler;
            _logger = logger;
            _options = options.Value;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                // 检查是否应该处理此异常
                if (!ShouldHandleException(ex, context))
                {
                    throw; // 重新抛出异常，让其他中间件处理
                }

                await HandleExceptionAsync(context, ex);
            }
        }

        private async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            var errorInfo = _errorHandler.HandleException(exception);

            // 记录异常日志
            LogException(context, exception, errorInfo);

            // 设置响应状态码
            context.Response.StatusCode = (int)(errorInfo.HttpStatusCode ?? HttpStatusCode.InternalServerError);

            // 设置响应内容类型
            context.Response.ContentType = "application/json";

            // 添加安全头
            AddSecurityHeaders(context);

            // 返回错误响应
            var errorResponse = _errorHandler.CreateErrorResponse(errorInfo);

            // 如果是开发环境，添加详细错误信息
            if (_options.IncludeExceptionDetails && _options.IsDevelopment)
            {
                errorResponse.Error.StackTrace = exception.StackTrace;
                errorResponse.Error.InnerException = GetInnerExceptionMessage(exception);
            }

            await context.Response.WriteAsJsonAsync(errorResponse);
        }

        private bool ShouldHandleException(Exception exception, HttpContext context)
        {
            // 检查异常类型过滤
            if (_options.ExceptionFilters.Any())
            {
                foreach (var filter in _options.ExceptionFilters)
                {
                    if (filter.ShouldHandle(exception, context))
                    {
                        return true;
                    }
                }
            }

            // 检查请求路径过滤
            if (_options.ExcludedPaths.Any(path => context.Request.Path.StartsWithSegments(path, StringComparison.OrdinalIgnoreCase)))
            {
                return false;
            }

            // 检查HTTP状态码
            var statusCode = exception switch
            {
                ArgumentException => HttpStatusCode.BadRequest,
                UnauthorizedAccessException => HttpStatusCode.Unauthorized,
                NotImplementedException => HttpStatusCode.NotImplemented,
                TimeoutException => HttpStatusCode.RequestTimeout,
                _ => HttpStatusCode.InternalServerError
            };

            // 某些状态码不在此中间件中处理
            return statusCode != HttpStatusCode.NotFound;
        }

        private void LogException(HttpContext context, Exception exception, ErrorInfo errorInfo)
        {
            var logLevel = exception switch
            {
                NotFoundException _ => LogLevel.Information,
                ValidationException _ => LogLevel.Warning,
                AuthorizationException _ => LogLevel.Warning,
                ConcurrencyException _ => LogLevel.Warning,
                MatrixFramework.Shared.Application.Exceptions.BusinessException _ => LogLevel.Warning,
                _ => LogLevel.Error
            };

            var logData = new
            {
                RequestId = context.TraceIdentifier,
                UserId = GetUserId(context),
                RequestPath = context.Request.Path,
                RequestMethod = context.Request.Method,
                UserAgent = context.Request.Headers["User-Agent"].ToString(),
                ClientIP = GetClientIP(context),
                ErrorCode = errorInfo.Code,
                ErrorMessage = errorInfo.Message,
                ErrorType = exception.GetType().Name,
                Exception = exception
            };

            _logger.Log(logLevel, exception, "请求处理异常: {@LogData}", logData);
        }

        private void AddSecurityHeaders(HttpContext context)
        {
            // 防止点击劫持
            context.Response.Headers["X-Content-Type-Options"] = "nosniff";

            // 防止MIME类型嗅探
            context.Response.Headers["X-Content-Type-Options"] = "nosniff";

            // XSS保护
            context.Response.Headers["X-XSS-Protection"] = "1; mode=block";

            // 强制HTTPS（如果配置了）
            if (_options.ForceHttps && !context.Request.IsHttps)
            {
                context.Response.Headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains";
            }

            // CSP头部（如果配置了）
            if (!string.IsNullOrEmpty(_options.ContentSecurityPolicy))
            {
                context.Response.Headers["Content-Security-Policy"] = _options.ContentSecurityPolicy;
            }

            // 隐藏服务器信息
            context.Response.Headers["Server"] = "MatrixFramework";

            // 隐藏ASP.NET版本
            context.Response.Headers["X-Powered-By"] = "ASP.NET";
            context.Response.Headers["X-ASPNET-VERSION"] = Environment.Version.ToString();
        }

        private string? GetUserId(HttpContext context)
        {
            // 从当前用户上下文获取用户ID
            // 这里需要根据实际的用户认证系统来实现
            return context.User?.Identity?.Name;
        }

        private string GetClientIP(HttpContext context)
        {
            var xForwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (!string.IsNullOrEmpty(xForwardedFor))
            {
                return xForwardedFor.Split(',')[0].Trim();
            }

            var xRealIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            if (!string.IsNullOrEmpty(xRealIp))
            {
                return xRealIp;
            }

            return context.Connection.RemoteIpAddress?.ToString();
        }

        private string? GetInnerExceptionMessage(Exception exception)
        {
            if (exception.InnerException == null)
                return null;

            return exception.InnerException.Message;
        }
    }

    /// <summary>
    /// 全局异常处理选项
    /// </summary>
    public class GlobalExceptionHandlingOptions
    {
        /// <summary>
        /// 是否包含异常详细信息
        /// </summary>
        public bool IncludeExceptionDetails { get; set; } = false;

        /// <summary>
        /// 是否为开发环境
        /// </summary>
        public bool IsDevelopment { get; set; }

        /// <summary>
        /// 是否强制HTTPS
        /// </summary>
        public bool ForceHttps { get; set; } = false;

        /// <summary>
        /// 内容安全策略
        /// </summary>
        public string? ContentSecurityPolicy { get; set; }

        /// <summary>
        /// 排除的请求路径
        /// </summary>
        public List<string> ExcludedPaths { get; set; } = new();

        /// <summary>
        /// 异常过滤器
        /// </summary>
        public List<IExceptionFilter> ExceptionFilters { get; set; } = new();
    }

    /// <summary>
    /// 异常过滤器接口
    /// </summary>
    public interface IExceptionFilter
    {
        /// <summary>
        /// 判断是否应该处理此异常
        /// </summary>
        /// <param name="exception">异常对象</param>
        /// <param name="context">HTTP上下文</param>
        /// <returns>是否应该处理</returns>
        bool ShouldHandle(Exception exception, HttpContext context);
    }

    /// <summary>
    /// 异常过滤器基类
    /// </summary>
    public abstract class ExceptionFilterBase : IExceptionFilter
    {
        /// <summary>
        /// 异常类型过滤器
        /// </summary>
        protected Type ExceptionType { get; set; }

        public virtual bool ShouldHandle(Exception exception, HttpContext context)
        {
            return ExceptionType.IsAssignableFrom(exception.GetType());
        }
    }

    /// <summary>
    /// HTTP异常过滤器
    /// </summary>
    public class HttpExceptionFilter : ExceptionFilterBase
    {
        public HttpExceptionFilter()
        {
            ExceptionType = typeof(HttpException);
        }
    }

    /// <summary>
    /// 业务异常过滤器
    /// </summary>
    public class BusinessExceptionFilter : ExceptionFilterBase
    {
        public BusinessExceptionFilter()
        {
            ExceptionType = typeof(MatrixFramework.Shared.Application.Exceptions.BusinessException);
        }
    }

    /// <summary>
    /// 路径异常过滤器
    /// </summary>
    public class PathExceptionFilter : IExceptionFilter
    {
        private readonly List<string> _excludedPaths;
        private readonly List<string> _includedPaths;

        public PathExceptionFilter()
        {
            _excludedPaths = new List<string>();
            _includedPaths = new List<string>();
        }

        public PathExceptionFilter ExcludePaths(params string[] paths)
        {
            _excludedPaths.AddRange(paths);
            return this;
        }

        public PathExceptionFilter IncludePaths(params string[] paths)
        {
            _includedPaths.AddRange(paths);
            return this;
        }

        public bool ShouldHandle(Exception exception, HttpContext context)
        {
            var path = context.Request.Path;

            // 如果配置了包含路径，只有包含的路径才处理
            if (_includedPaths.Any())
            {
                return _includedPaths.Any(p => path.StartsWithSegments(p, StringComparison.OrdinalIgnoreCase));
            }

            // 如果配置了排除路径，排除的路径不处理
            return !_excludedPaths.Any(p => path.StartsWithSegments(p, StringComparison.OrdinalIgnoreCase));
        }
    }

    /// <summary>
    /// HTTP异常扩展
    /// </summary>
    public class HttpException : Exception
    {
        public int StatusCode { get; }
        public string? ErrorCode { get; }
        public new object? Data { get; }

        public HttpException(int statusCode, string message, string? errorCode = null, object? data = null)
            : base(message)
        {
            StatusCode = statusCode;
            ErrorCode = errorCode;
            Data = data;
        }

        public HttpException(HttpStatusCode statusCode, string message, string? errorCode = null, object? data = null)
            : this((int)statusCode, message, errorCode, data)
        {
        }
    }

    /// <summary>
    /// 中间件扩展方法
    /// </summary>
    public static class GlobalExceptionHandlingMiddlewareExtensions
    {
        /// <summary>
        /// 添加全局异常处理中间件
        /// </summary>
        public static IApplicationBuilder UseGlobalExceptionHandling(this IApplicationBuilder app, Action<GlobalExceptionHandlingOptions>? configureOptions = null)
        {
            var options = new GlobalExceptionHandlingOptions();

            // 判断是否为开发环境
            var environment = app.ApplicationServices.GetService<IHostEnvironment>();
            options.IsDevelopment = environment?.IsDevelopment() ?? false;

            // 如果是开发环境，默认包含异常详细信息
            if (options.IsDevelopment)
            {
                options.IncludeExceptionDetails = true;
            }

            // 应用自定义配置
            configureOptions?.Invoke(options);

            return app.UseMiddleware<GlobalExceptionHandlingMiddleware>(options);
        }

        /// <summary>
        /// <summary>
        /// 添加全局异常处理中间件（使用预配置选项）
        /// </summary>
        public static IApplicationBuilder UseGlobalExceptionHandling(this IApplicationBuilder app, GlobalExceptionHandlingOptions options)
        {
            return app.UseMiddleware<GlobalExceptionHandlingMiddleware>(options);
        }

        /// <summary>
        /// <summary>
        /// 添加异常过滤器
        /// </summary>
        public static GlobalExceptionHandlingOptions AddExceptionFilter<T>(this GlobalExceptionHandlingOptions options) where T : IExceptionFilter, new()
        {
            options.ExceptionFilters.Add(new T());
            return options;
        }

        /// <summary>
        /// <summary>
        /// 添加异常过滤器
        /// </summary>
        public static GlobalExceptionHandlingOptions AddExceptionFilter(this GlobalExceptionHandlingOptions options, IExceptionFilter filter)
        {
            options.ExceptionFilters.Add(filter);
            return options;
        }

        /// <summary>
        /// <summary>
        /// 排除请求路径
        /// </summary>
        public static GlobalExceptionHandlingOptions ExcludePaths(this GlobalExceptionHandlingOptions options, params string[] paths)
        {
            options.ExcludedPaths.AddRange(paths);
            return options;
        }

        /// <summary>
        /// <summary>
        /// 强制HTTPS
        /// </summary>
        public static GlobalExceptionHandlingOptions ForceHttps(this GlobalExceptionHandlingOptions options, bool force = true)
        {
            options.ForceHttps = force;
            return options;
        }

        /// <summary>
        /// <summary>
        /// 设置内容安全策略
        /// </summary>
        public static GlobalExceptionHandlingOptions SetContentSecurityPolicy(this GlobalExceptionHandlingOptions options, string csp)
        {
            options.ContentSecurityPolicy = csp;
            return options;
        }

        /// <summary>
        /// <summary>
        /// 在开发环境中包含异常详细信息
        /// </summary>
        public static GlobalExceptionHandlingOptions IncludeExceptionDetailsInDevelopment(this GlobalExceptionHandlingOptions options, bool include = true)
        {
            options.IncludeExceptionDetails = include;
            return options;
        }
    }
}